﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Pavilion.GameTools;
using Microsoft.Xna.Framework;

namespace Pavilion.Locks
{
    public enum Direction { Left, Right, Top, Bottom, Center }
    class ItemDistanceLock : ILock
    {
        public GameItem FocusGameItem { get; set; }
        public string GameItemName { get; set; }
        public float Distance { get; set; }
        public Direction PositionSection { get; set; }

        public ILock Clone()
        {
            return new ItemDistanceLock()
            {
                FocusGameItem = this.FocusGameItem,
                GameItemName = this.GameItemName,
                Distance = this.Distance,
                PositionSection = this.PositionSection
            };
        }

        public void Deserialize(XElement lockElement, string resourceName)
        {
            string focusGameItemName = lockElement.Attribute("FocusGameItem").Value;

            if (!string.IsNullOrEmpty(focusGameItemName))
                FocusGameItem = GameItemManager.Instance[focusGameItemName];

            Distance = GameEngine.ParseObject<float>(lockElement.Attribute("Distance").Value);
            PositionSection = GameEngine.EnumParse<Direction>(lockElement.Attribute("PositionSection").Value);
        }

        public XElement Serialize()
        {
            XElement lockElement = new XElement("Lock");

            lockElement.Add(new XAttribute("FocusGameItem", FocusGameItem.Name));
            lockElement.Add(new XAttribute("Distance", Distance));
            lockElement.Add(new XAttribute("PositionSection", PositionSection));

            return lockElement;
        }

        public LockMonitorBase CreateLockMonitor(GameItem gameItem)
        {
            PolygonPhysicalData targetPolygonData = gameItem.ObtainTool<PhysicalTypeTool>().PolygonData;
            PolygonPhysicalData focusPolygonData = null;

            if (FocusGameItem != null)
                focusPolygonData = FocusGameItem.ObtainTool<PhysicalTypeTool>().PolygonData;

            return new ItemDistanceLockMonitor(this, focusPolygonData, targetPolygonData);
        }

        public override string ToString()
        {
            return this.GetType().Name;
        }

        public class ItemDistanceLockMonitor : LockMonitorBase
        {
            public override ILock Lock { get { return lockItem; } }

            private PolygonPhysicalData focusPolygonData, sourcePolygonData;
            private ItemDistanceLock lockItem;

            public ItemDistanceLockMonitor(ItemDistanceLock lockItem, PolygonPhysicalData focusPolygonData, PolygonPhysicalData sourcePolygonData)
            {
                this.lockItem = lockItem;
                this.focusPolygonData = focusPolygonData;
                this.sourcePolygonData = sourcePolygonData;
            }

            public override void Dispose()
            {
                if (focusPolygonData != null)
                {
                    sourcePolygonData.PositionChanged -= PolygonData_PositionChanged;
                    focusPolygonData.PositionChanged -= PolygonData_PositionChanged;
                }

                sourcePolygonData = null;
                focusPolygonData = null;
            }

            public override void Load(GameItem gameItem)
            {
                if (focusPolygonData != null)
                {
                    focusPolygonData.PositionChanged += PolygonData_PositionChanged;
                    sourcePolygonData.PositionChanged += PolygonData_PositionChanged;
                }

                UpdateLock();
            }

            public override void UpdateLock()
            {
                if (focusPolygonData == null)
                    return;

                Vector2 actualPosition = sourcePolygonData.Position + new Vector2(lockItem.Distance, lockItem.Distance);

                if (lockItem.PositionSection == Direction.Left)
                    IsOpen = actualPosition.X > focusPolygonData.Position.X;
                else if (lockItem.PositionSection == Direction.Right)
                    IsOpen = actualPosition.X < focusPolygonData.Position.X;
                else if (lockItem.PositionSection == Direction.Bottom)
                    IsOpen = actualPosition.Y < focusPolygonData.Position.Y;
                else if (lockItem.PositionSection == Direction.Top)
                    IsOpen = actualPosition.Y > focusPolygonData.Position.Y;
            }

            private void PolygonData_PositionChanged(PhysicalData physicalData, float xDistance, float yDistance)
            {
                UpdateLock();
            }
        }
    }
}
